package main;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ClusterSort2 {

	String termCount;

	String termFormatted;

	String topPassages;

	int clusterSize;

	int outputLine = 1000;

	String outputFile;

	List topics;

	final static int totalSize = 1000;

	public ClusterSort2() {

		initConfig();

		read();
		System.out.println("sort begin.............");
		Date begin = new Date();
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile + "-clusterNum"));
			for (Iterator iter = topics.iterator(); iter.hasNext();) {
				Topic topic = (Topic) iter.next();
				List clusters = new ArrayList();
				clusters = cluster(topic.getPassages(), clusters);
				// print clusters num
				bw.write(topic.getId() + "," + clusters.size() + "\r\n");
				List list = resort(clusters);
				filtSamePassage(list);
				topic.setSortedPassages(list);
			}
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("sort end.............");
		Date end = new Date();
		write(topics);
		System.out.println("sort time:" + (end.getTime() - begin.getTime()));

	}

	private void write(List topics) {
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile));
			for (Iterator iter = topics.iterator(); iter.hasNext();) {
				Topic topic = (Topic) iter.next();
				int i = 0;
				for (Iterator itP = topic.getSortedPassages().iterator(); itP.hasNext() && i < outputLine; i++) {
					Passage psg = (Passage) itP.next();
					bw.write(psg.getOutString() + "\r\n");
					System.out.println(psg);
				}

			}
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private List cluster(List psgs, List clusters) {
		Passage firstPsg = (Passage) psgs.get(0);
		List clusterX = new ArrayList();
		for (Iterator itp = psgs.iterator(); itp.hasNext();) {
			Passage psg = (Passage) itp.next();
			BigDecimal simRank = calSimRank(firstPsg, psg);
			psg.setSimilarityRank(simRank);
			if (simRank.intValue() == 1) {
				clusterX.add(psg);
			}
		}
		clusters.add(clusterX);
		psgs.removeAll(clusterX);
		// Collections.sort(psgs);
		// List samePsgs = psgs.subList(0, clusterSize);
		// int clusterPos = (totalSize - psgs.size()) / clusterSize;
		// int clusterNum = totalSize / clusterSize;
		// for (int i = 0; i < topx.size(); i++) {
		// sortedPsgs.set(i * clusterNum + clusterPos, topx.get(i));
		// }
		// List leftPsgs = psgs.subList(clusterSize, psgs.size());
		if (psgs.size() > 0) {
			cluster(psgs, clusters);
		}
		return clusters;
	}

	private List resort(List clusters) {
		int clusterSize = 0;
		int clusterNum = clusters.size();
		for (int i = 0; i < clusterNum; i++) {
			List clusterX = (List) clusters.get(i);
			if (clusterX.size() > clusterSize) {
				clusterSize = clusterX.size();
			}
		}

		List newlist = new ArrayList();
		// init list
		for (int i = 0; i < clusterSize * clusterNum; i++) {
			newlist.add(null);
		}

		// set psg to new list
		for (int i = 0; i < clusterNum; i++) {
			List clusterX = (List) clusters.get(i);
			for (int j = 0; j < clusterX.size(); j++) {
				newlist.set(clusterNum * j + i, clusterX.get(j));
			}
		}

		// remove null
		for (int i = newlist.size() - 1; i >= 0; i--) {
			if (newlist.get(i) == null) {
				newlist.remove(i);
			}
		}

		return newlist;
	}

	private void filtSamePassage(List psgs) {

		List removeIndex = new ArrayList();
		for (int i = 1; i < psgs.size(); i++) {
			Passage psg1 = (Passage) psgs.get(0);
			Passage psg2 = (Passage) psgs.get(i);

			if (psg1.getDocumentID().equals(psg2.getDocumentID())) {
				removeIndex.add(new Integer(i));
			}
		}
		// remove psgs
		if (removeIndex.size() > 0) {
			for (int i = psgs.size(); i >= 0; i--) {
				for (int j = 0; j < removeIndex.size(); j++) {
					if (i == ((Integer) removeIndex.get(j)).intValue()) {
						psgs.remove(i);
					}
				}
			}
			filtSamePassage(psgs);
		}
	}

	/**
	 * @param firstPsg
	 * @param psg
	 * @return
	 */
	private BigDecimal calSimRank(Passage firstPsg, Passage psg) {
		String[] firstTerms = firstPsg.getFoundTerms();
		String[] theTerms = psg.getFoundTerms();
		int totalNum = firstTerms.length;
		if (theTerms.length > firstTerms.length) {
			totalNum = theTerms.length;
		}
		int sameNum = 0;
		for (int i = 0; i < firstTerms.length; i++) {
			for (int j = 0; j < theTerms.length; j++) {
				if (firstTerms[i].equals(theTerms[j])) {
					sameNum++;
				}
			}
		}
		BigDecimal simRank = new BigDecimal(sameNum).divide(new BigDecimal(totalNum), 4, BigDecimal.ROUND_HALF_EVEN);
		return simRank;
	}

	private void read() {
		topics = new ArrayList();
		System.out.println("read file begin.............");
		try {

			// readTopPassages();
			readTermFormatted();

			readTermCount();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("read file end.............");

	}

	/**
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void readTermFormatted() throws FileNotFoundException, IOException {
		BufferedReader fmt_file = new BufferedReader(new FileReader(termFormatted));
		for (String tmp = fmt_file.readLine(); tmp != null; tmp = fmt_file.readLine()) {
			String[] tmpArr = tmp.split(" ");
			if (tmpArr.length == 7) {
				Topic topic = getTopic(tmpArr[0]);
				if (topic == null) {
					topic = new Topic();
					topic.setId(tmpArr[0]);
					topics.add(topic);
				}

				Passage psg = new Passage();
				psg.setDocumentID(tmpArr[1]);
				psg.setOutString(tmp);
				topic.addPassage(psg);
			} else {
				System.err.println("file format error!");
			}
		}
		fmt_file.close();
	}

	/**
	 * @param id
	 * @return
	 */
	private Topic getTopic(String id) {
		for (Iterator iter = topics.iterator(); iter.hasNext();) {
			Topic thetopic = (Topic) iter.next();
			if (id.equals(thetopic.getId())) {
				return thetopic;
			}
		}
		return null;
	}

	/**
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private BufferedReader readTermCount() throws FileNotFoundException, IOException {
		BufferedReader top_file = new BufferedReader(new FileReader(termCount));
		Topic topic = null;
		int i = 0;
		for (String tmp = top_file.readLine(); tmp != null; tmp = top_file.readLine()) {
			if (tmp.startsWith("Topic#")) {
				String topicid = tmp.replaceFirst("Topic#", "");
				topic = this.getTopic(topicid);
				i = 0;
			} else if (tmp.startsWith("passage")) {
				if (topic != null) {
					List psgs = topic.getPassages();

					Passage psg = (Passage) psgs.get(i);
					Pattern p = Pattern.compile("passage .* terms was found >> ");
					Matcher m = p.matcher(tmp);
					StringBuffer sb = new StringBuffer();
					if (m.find()) {
						m.appendReplacement(sb, "");
						m.appendTail(sb);
					} else {
						Pattern p2 = Pattern.compile("passage .* terms was found\\.");
						Matcher m2 = p2.matcher(tmp);
						if (m2.find()) {
							sb = new StringBuffer();
						}
					}
					psg.setTerms(sb.toString());
					psg.setFoundTerms(sb.toString().split(" "));
					i++;
				}
			}
		}
		top_file.close();
		return top_file;
	}

	/**
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void initConfig() {
		try {
			BufferedReader conf_file = new BufferedReader(new FileReader("config/cluster_sort_config2.properties"));
			for (String tmp = conf_file.readLine(); tmp != null; tmp = conf_file.readLine()) {
				String[] conf = tmp.split("=");
				if (conf[0].equals("term-count-of-txts-name")) {
					this.termCount = conf[1];
				} else if (conf[0].equals("formatted-combined-txt-name")) {
					this.termFormatted = conf[1];
				} else if (conf[0].equals("top-passages-name")) {
					this.topPassages = conf[1];
				} else if (conf[0].equals("cluster-size")) {
					this.clusterSize = new Integer(conf[1]).intValue();
				} else if (conf[0].equals("output-line")) {
					this.outputLine = new Integer(conf[1]).intValue();
				} else if (conf[0].equals("output-file-name")) {
					this.outputFile = conf[1];
				}
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		ClusterSort2 cs = new ClusterSort2();

	}
}
